#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
使用Nuitka打包MySQLPass程序
此脚本将MySQLPass打包为独立可执行文件
"""

import os
import sys
import subprocess
import shutil
import argparse
from datetime import datetime

# 项目基本信息
PROJECT_NAME = "MySQLPass"
VERSION = "1.0.0"
MAIN_SCRIPT = "main.py"
BUILD_DIR = "nuitka_build"
OUTPUT_DIR = "nuitka_dist"


def clean_build():
    """清理之前的构建文件"""
    print(f"正在清理之前的构建文件...")
    
    # 删除构建目录
    if os.path.exists(BUILD_DIR):
        try:
            shutil.rmtree(BUILD_DIR)
            print(f"已删除构建目录: {BUILD_DIR}")
        except Exception as e:
            print(f"清理构建目录时出错: {e}")
    
    # 删除输出目录
    if os.path.exists(OUTPUT_DIR):
        try:
            shutil.rmtree(OUTPUT_DIR)
            print(f"已删除输出目录: {OUTPUT_DIR}")
        except Exception as e:
            print(f"清理输出目录时出错: {e}")
    
    # 删除可能的临时文件
    for root, dirs, files in os.walk('.'):
        for file in files:
            if file.endswith('.build') or file.endswith('.dist'):
                try:
                    os.remove(os.path.join(root, file))
                except:
                    pass


def build_with_nuitka(onefile=True, console=False, verbose=False):
    """使用Nuitka打包程序
    
    Args:
        onefile: 是否打包为单文件
        console: 是否显示控制台窗口
        verbose: 是否显示详细输出
    """
    print(f"开始使用Nuitka打包{PROJECT_NAME} v{VERSION}...")
    
    # 清理之前的构建
    clean_build()
    
    # 构建Nuitka命令参数
    cmd = [
        sys.executable,
        "-m", "nuitka",
        MAIN_SCRIPT,
        f"--output-dir={BUILD_DIR}",
        f"--product-name={PROJECT_NAME}",
        f"--product-version={VERSION}",
        "--company-name=MySQLPass团队",
        "--copyright=© 2025 MySQLPass团队. All rights reserved.",
        "--include-package=src",  # 包含src包
        "--follow-imports",       # 跟随导入
        "--plugin-enable=tk-inter", # 启用tkinter插件
        "--msvc=latest",           # 使用最新的MSVC编译器，避免下载MinGW
    ]
    
    # 是否打包为单文件
    if onefile:
        cmd.append("--onefile")
        cmd.append(f"--output-filename={PROJECT_NAME}.exe")
    
    # 是否显示控制台窗口
    if not console:
        cmd.append("--windows-disable-console")
    
    # 是否显示详细输出
    if verbose:
        cmd.append("--verbose")
    else:
        # 不使用--quiet，以便看到一些基本的打包进度信息
        pass
    
    # 添加必要的依赖项
    # 使用更精简的依赖配置，让Nuitka自动检测和包含所需的依赖
    cmd.extend([
        "--include-package=src",
        "--include-package=pymysql",
        "--include-package=PIL",
        "--include-package=pandas",
        "--include-package=numpy",
    ])
    
    print(f"执行命令: {' '.join(cmd)}")
    
    try:
        # 执行Nuitka命令
        start_time = datetime.now()
        result = subprocess.run(cmd, check=True, capture_output=not verbose)
        end_time = datetime.now()
        
        print(f"\n打包完成！耗时: {end_time - start_time}")
        
        # 如果是单文件模式，复制可执行文件到输出目录
        if onefile:
            if not os.path.exists(OUTPUT_DIR):
                os.makedirs(OUTPUT_DIR)
            
            exe_path = os.path.join(BUILD_DIR, f"{PROJECT_NAME}.exe")
            if os.path.exists(exe_path):
                shutil.copy2(exe_path, OUTPUT_DIR)
                print(f"已将可执行文件复制到: {os.path.join(OUTPUT_DIR, f'{PROJECT_NAME}.exe')}")
            else:
                print(f"警告: 未找到生成的可执行文件: {exe_path}")
                # 查找可能的可执行文件
                for root, _, files in os.walk(BUILD_DIR):
                    for file in files:
                        if file.endswith('.exe'):
                            found_exe = os.path.join(root, file)
                            shutil.copy2(found_exe, os.path.join(OUTPUT_DIR, f"{PROJECT_NAME}.exe"))
                            print(f"已找到并复制可执行文件: {found_exe} -> {os.path.join(OUTPUT_DIR, f'{PROJECT_NAME}.exe')}")
                            break
        else:
            # 如果不是单文件模式，将整个dist目录复制到输出目录
            dist_dir = os.path.join(BUILD_DIR, f"{os.path.splitext(MAIN_SCRIPT)[0]}.dist")
            if os.path.exists(dist_dir):
                if os.path.exists(OUTPUT_DIR):
                    shutil.rmtree(OUTPUT_DIR)
                shutil.copytree(dist_dir, OUTPUT_DIR)
                print(f"已将dist目录复制到: {OUTPUT_DIR}")
            else:
                print(f"警告: 未找到生成的dist目录: {dist_dir}")
        
        return True
    except subprocess.CalledProcessError as e:
        print(f"打包失败！错误码: {e.returncode}")
        if not verbose:
            print(f"错误输出: {e.stderr.decode('utf-8', errors='ignore')}")
        return False
    except Exception as e:
        print(f"打包过程中发生错误: {e}")
        return False


def verify_build():
    """验证构建结果"""
    print(f"\n正在验证构建结果...")
    
    # 检查可执行文件是否存在
    exe_path = os.path.join(OUTPUT_DIR, f"{PROJECT_NAME}.exe")
    if os.path.exists(exe_path):
        print(f"✓ 找到可执行文件: {exe_path}")
        print(f"  文件大小: {os.path.getsize(exe_path) / (1024 * 1024):.2f} MB")
        return True
    else:
        print(f"✗ 未找到可执行文件: {exe_path}")
        # 检查OUTPUT_DIR目录内容
        if os.path.exists(OUTPUT_DIR):
            print(f"  {OUTPUT_DIR}目录内容:")
            for item in os.listdir(OUTPUT_DIR):
                item_path = os.path.join(OUTPUT_DIR, item)
                if os.path.isfile(item_path):
                    print(f"    - {item} ({os.path.getsize(item_path) / 1024:.2f} KB)")
                else:
                    print(f"    - {item}/")
        return False


def main():
    """主函数"""
    # 创建命令行参数解析器
    parser = argparse.ArgumentParser(description=f'使用Nuitka打包{PROJECT_NAME}程序')
    parser.add_argument('--debug', action='store_true', help='调试模式，显示控制台窗口')
    parser.add_argument('--verbose', action='store_true', help='显示详细输出信息')
    parser.add_argument('--no-onefile', action='store_true', help='不生成单文件，生成目录模式')
    
    # 解析命令行参数
    args = parser.parse_args()
    
    # 执行打包
    success = build_with_nuitka(
        onefile=not args.no_onefile,
        console=args.debug,
        verbose=args.verbose
    )
    
    # 验证构建结果
    if success:
        verify_build()
    
    # 输出最终状态
    if success:
        print(f"\n🎉 {PROJECT_NAME} 打包成功！")
        print(f"可执行文件位于: {os.path.abspath(OUTPUT_DIR)}")
    else:
        print(f"\n❌ {PROJECT_NAME} 打包失败！")
        sys.exit(1)


if __name__ == "__main__":
    main()